iT邦幫忙

2024 iThome 鐵人賽

DAY 19
0
Modern Web

現在就學React.js 系列 第 19

React中處理副作用的利器 - useEffect - Day19

  • 分享至 

  • xImage
  •  

了解useEffect之前,先來知道 何謂 副作用吧!

什麼是副作用 (Side Effects)?

在日常生活中,我們常聽到「副作用」這個詞。例如,當我們服用藥物時,藥袋上可能會寫明該藥物的副作用,如嗜睡、頭痛或腸胃不適。雖然副作用通常被視為不良反應,但它們也可能帶來一些正面的影響,例如加快病情康復。

在程式中,副作用指的是在函式運行期間對外部環境的任何影響或變化。這些影響可能包括修改全域變數、手動更改 DOM 元素、執行 API 請求,甚至改變傳入參數。這些操作都會影響到函式外部的狀態,使程式變得難以預測和維護。

JavaScript 中的副作用範例

以下是一些常見的副作用操作:


// 修改全域變數或物件屬性
let count = 0;

function increment() {
  count += 1; // 修改全域變數 count
}

increment();
console.log("全域變數 count 的值:", count); // 1

// 修改 DOM
function changeTitle(newTitle) {
  document.title = newTitle; // 修改瀏覽器的標題
}

changeTitle("新標題");

// 執行 API 操作
function fetchData() {
  fetch("https://api.example.com/data")
    .then(response => response.json())
    .then(data => console.log("網路請求獲得的資料:", data)); // 進行網路請求
}

fetchData();

// 改變傳入參數
function addElement(arr, element) {
  arr.push(element); // 修改傳入的陣列
}

const myArray = [1, 2, 3];
addElement(myArray, 4);
console.log("修改後的陣列:", myArray); // [1, 2, 3, 4]

這些副作用都會對函式外部的狀態產生某種改變,這會使程式變得難以除錯和維護。

React 中的 useEffect

在 React 開發中,useEffect 是一個非常重要的 Hook,用來處理副作用 (side effects)。它的主要功能是在組件渲染後執行一些會影響外部環境的操作(如發送網路請求、修改 DOM 等),這有助於將副作用邏輯與渲染邏輯分離,讓程式碼更加清晰且易於維護。

使用方式

useEffect 的使用非常簡單,通常為以下幾個步驟:

  1. 從 React 中載入 useEffect
  2. 將要執行的 effect 帶入 useEffect 函式中
  3. 如果有依賴項 (dependencies),將它們傳入第二個參數陣列

從 React 中載入 useEffect

首先,我們需要從 React 中引入 useEffect,這樣才能在功能組件中使用它。


import { useEffect } from 'react';

將要執行的 effect 帶入 useEffect 函式中

useEffect 會在組件渲染完成後被執行,在這個函式中,你可以放入所有需要在渲染後執行的副作用操作。


useEffect(() => {
  //...要執行的 effect
});

這個函式中的邏輯會在組件渲染完畢後自動執行,適合用來處理需要在畫面顯示後進行的操作。

若有依賴項,將它們傳入第二個參數陣列

useEffect 的第二個參數是一個陣列,稱為依賴項 (dependencies)。當陣列中的依賴項發生變化時,useEffect 中的函式才會重新執行。這樣可以避免不必要的重複執行,從而提升效能。


useEffect(() => {
  //...要執行的 effect
}, [dependencies]);

如果你傳入了一個空陣列 []useEffect 只會在組件首次渲染時執行一次。

useEffect 的四種使用方式

1. 只在畫面初次渲染後執行


useEffect(() => {
  console.log("mounted");
}, [])

這種方式只在組件初次渲染後執行一次。使用這種方法時,我們將 useEffect 的依賴性陣列設為空,表示它不依賴於任何外部值,因此只會執行一次。

2. 每次組件更新時都執行


useEffect(() => {
  console.log("updated");
})

這種方式會在每次組件更新後執行。這種方法非常適合用來處理需要在每次渲染後進行的操作。

3. 依賴項變更時才執行


useEffect(() => {
  console.log("updated with dependencies");
}, [count])

在這種情況下,useEffect 只有在指定的依賴項(例如 count)發生變更時才會執行。這樣可以避免在每次渲染時都執行昂貴的計算,從而提升效能。

4. 清理需被銷毀的副作用


useEffect(() => {
  const onMousedown = () => {
    console.log("mousedown");
  };
  window.addEventListener("mousedown", onMousedown);

  const timer = setInterval(() => {
    console.log('Hello React');
  }, 1000);

  return () => {
    console.log("cleanup");
    window.removeEventListener("mousedown", onMousedown);
    clearInterval(timer);
  };
});

在這個例子中,useEffect 返回了一個清理函式,用於在組件重新渲染或卸載時清除副作用。如果不清理這些副作用,可能會導致記憶體洩漏或性能問題。

useEffect 的常見應用情境如下:

  1. 操作 DOM、動畫:在組件渲染後執行 DOM 操作或觸發動畫。
  2. 事件監聽 (addEventListener/removeEventListener):為避免重複監聽事件,在組件掛載後新增事件監聽器,並在組件卸載前移除。
  3. 定時器 (setInterval/clearInterval):避免重複設置定時器,通常在組件掛載後設置,並在組件卸載前清除。
  4. 使用外部函式庫:避免 React 的渲染方式與外部函式庫的運作發生衝突。
  5. 向後端呼叫 API:在組件建立時呼叫一次 API,適合用於抓取數據的操作。

結論

副作用是 JavaScript 和其他程式語言中的一個關鍵概念。理解並有效地管理副作用有助於撰寫更穩健和可預測的程式碼。在 React 中,useEffect 提供了一個好的方式來處理副作用,使得組件的生命週期管理更加簡單。透過合理使用 useEffect,我們可以確保程式邏輯和副作用邏輯保持分離,從而提升應用程式的可維護性和效能。

參考資料


上一篇
綜合練習-TodoList 實作(下) Day18
下一篇
在 React 中使用 Axios 進行非同步請求 - Day20
系列文
現在就學React.js 31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言